iT邦幫忙

2023 iThome 鐵人賽

DAY 7
0

網頁常見的功能之一就是表單,像是註冊、輸入個人資料、後臺建立管理資料等都需要有表單輸入的功能,另外最好還有前端能事先對表單的輸入內容進行檢查,通過後才發給後端。

為了達成這些功能我常用的組合是 react-hook-form 搭配 yup ,首先安裝套件。

pnpm add -D react-hook-form @hookform/resolvers yup 

示範一個基礎應用:

'use client';
import { useForm, Controller } from 'react-hook-form';
import TextField from '@mui/material/TextField';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
import { Button } from '@mui/material';

export default async function ContactForm() {
  const { control, handleSubmit } = useForm({
    resolver: yupResolver(
      yup.object({
        email: yup.string().email().required(),
      })
    ),
  });

  const onSubmit = handleSubmit((data) => {
    console.log(data);
  });

  return (
    <div>
      <Controller
        name="email"
        control={control}
        defaultValue=""
        render={({ field, fieldState }) => (
          <TextField
            label="Email"
            {...field}
            error={!!fieldState.error}
            helperText={fieldState.error ? fieldState.error.message : null}
          />
        )}
      />
      <Button onClick={onSubmit}>Submit</Button>
    </div>
  );
}

解說開始,首先是 useForm 這個 hook,是整個表單的集中管理區,搜集表單內容、檢查、送出都是經由這邊提供的 api。

而因為要搭配 MUI 使用,所以藉由 Controller 這個元件將表單控制的相關內容提供給 MUI 的元件。

主要的控制項會是 field 當中的 valueonChange ,因為 key 名稱完全相同所以這邊用 {...field} 的寫法偷行數,實際展開來會像這樣:

<Controller
  name="email"
  control={control}
  defaultValue=""
  render={({ field: { value, onChange }, fieldState }) => (
    <TextField
      label="Email"
      value={value}
      onChange={onChange}
      error={!!fieldState.error}
      helperText={fieldState.error ? fieldState.error.message : null}
    />
  )}
/>

再來 useForm 上可以定義整個表單的格式驗證,這邊用的 yup ,而 react-hook-form 有特地為了 yup 製作轉換函式,將 yup 產生的檢查格式轉換成 react-hook-form 能使用的格式。

const { control, handleSubmit } = useForm({
  resolver: yupResolver(
    yup.object({
      email: yup.string().email().required(),
    })
  ),
});

如果欄位的格式驗證有誤,就能經由 Controller 的 fieldState 取得該欄位的錯誤訊息。

最後要將表單內容送出的話是經由 handleSubmit 進行。

handleSubmit 的第一個參數是當驗證通過後處理表單資訊的 callback ,通常就在這邊去呼叫 api。

另外 handleSubmit 的第二個參數是當格式驗證失敗後的處理,雖然錯誤訊息可以直接經由 Controller 提供所以這裡通常用不太上,但如果要觸發跳窗或通知的話可以在這邊處理。

const onSubmit = handleSubmit(
    (data) => {
      console.log(data);
    },
    (error) => {
      console.log(error);
    }
  );

react-hook-form 在使用上可以相當靈活,尤其是遇到一些樣式較複雜的表單的時候,可以將表單的各個區塊切出元件但保持 useForm 的集中管理功能,主要靠的是 useFormContext,對於程式碼切分非常方便。

'use client';
import {
  useForm,
  Controller,
  useFormContext,
  FormProvider,
} from 'react-hook-form';
import TextField from '@mui/material/TextField';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
import { Button } from '@mui/material';

function Field() {
  const methods = useFormContext();

  return (
    <Controller
      name="email"
      control={methods.control}
      defaultValue=""
      render={({ field, fieldState }) => (
        <TextField
          label="Email"
          {...field}
          error={!!fieldState.error}
          helperText={fieldState.error ? fieldState.error.message : null}
        />
      )}
    />
  );
}

export default async function ContactForm() {
  const methods = useForm({
    resolver: yupResolver(
      yup.object({
        email: yup.string().email().required(),
      })
    ),
  });

  const onSubmit = methods.handleSubmit(
    (data) => {
      console.log(data);
    },
    (error) => {
      console.log(error);
    }
  );

  return (
    <div>
      <FormProvider {...methods}>
        <Field />
      </FormProvider>
      <Button onClick={onSubmit}>Submit</Button>
    </div>
  );
}

上一篇
整合 MUI 跟 Tailwind 樣式設定
下一篇
加入 husky
系列文
組裝前端開發工具箱,從 NX 入手30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言